#define _CRT_SECURE_NO_DEPRECATE
#define _CRT_NONSTDC_NO_DEPRECATE
#include"StringPool.h"
#include"variable.h"
#include"Util.h"
#include<iostream>
#include<stdio.h>
#include"ParserOptions.h"
using namespace std;

void ParserOptions::init(){
	trainfile = NULL;
	testfile = NULL;
	trainforest = NULL;
	string tmp = "log.txt";
	logfile = pool->get(tmp);
	//testforest = NULL;
	train = false;
	eval = false;
	test = false;
	dev = false;
	devfile = NULL;
	tmp = "dep.model";
	modelName = pool->get(tmp);
	tmp = "punc";
	lossType = pool->get(tmp);
	createForest = true;
	tmp = "proj";
	decodeType = pool->get(tmp);
	tmp = "CONLL";
	format = pool->get(tmp);
	numIters = 10;
	tmp = "out.txt";
	outfile = pool->get(tmp);
	goldfile = NULL;
	trainK = 1;
	testK = 1;
	order = 1;
	tmp = "dependency";
	modelType = pool->get(tmp);
	tmp = "MIRA";
	learnModel = pool->get(tmp);
	labeled = false;
	hasEnd = false;
	useRelationalFeatures = false;
	discourseMode = false;
	root_type = 0;
	tmp = "normal";
	rootType = pool->get(tmp);
	pool_size = 0;
	map_size = 1000000;
	maxiter = 10000;
	thread_num = 1;
	C = 1.0;
	eta = 0.0001;
}

ParserOptions::ParserOptions(std::vector<string*> &args){
	init();
	vector<string*>::iterator iter;
	for(iter = args.begin(); iter != args.end(); iter++){
		bool flag = true;
		vector<string*>* pair = Util::split(*iter, ':');
		string* item = (*pair)[0];
		string* value = pair->size() > 1 ? (*pair)[1] : NULL;
		if(*item == "train"){
			train = true;
		}
		if(*item == "eval"){
			eval = true;
		}
		if(*item == "labeled"){
			labeled = (*value == "true") ? true : false;
		}
		if(*item == "has-end"){
			hasEnd = (*value == "true") ? true : false;
		}
		if(*item == "test"){
			test= true;
		}
		if(*item == "develop"){
			dev = true;
		}
		if(*item == "iters"){
			numIters = Util::stringToInt(value);
		}
		if(*item == "develop-file"){
			devfile = value;
			flag = false;
		}
		if(*item == "output-file"){
			pool->push_back(outfile);
			outfile = value;
			flag = false;
		}
		if(*item == "gold-file"){
			goldfile = value;
			flag = false;
		}
		if(*item == "train-file"){
			trainfile = value;
			flag = false;
		}
		if(*item == "test-file"){
			testfile = value;
			flag = false;
		}
		if(*item == "log-file"){
			pool->push_back(logfile);
			logfile = value;
			flag = false;
		}
		if(*item == "model-name"){
			pool->push_back(modelName);
			modelName = value;
			flag = false;
		}
		if(*item == "training-k"){
			trainK = Util::stringToInt(value);
		}
		if(*item == "map-size"){
			map_size = Util::stringToInt(value);
		}
		if(*item == "loss-type"){
			pool->push_back(lossType);
			lossType = value;
			flag = false;
		}
		if(*item == "order"){
			order = Util::stringToInt(value);
			if(order > 4 || order < 1){
				printf("Order %d is not valid\n", order);
			}
		}
		if(*item == "model-type"){
			pool->push_back(modelType);
			modelType = value;
			flag = false;
		}
		if(*item == "LA"){
			pool->push_back(learnModel);
			learnModel = value;
			flag = false;
		}
		if(*item == "cost"){
			C = Util::stringToDouble(value);
		}
		if(*item == "eta"){
			eta = Util::stringToDouble(value);
		}
		if(*item == "maxiter"){
			maxiter = Util::stringToInt(value);
		}
		if(*item == "thread-num"){
			thread_num = Util::stringToInt(value);
		}
		if(*item == "root-type"){
			pool->push_back(rootType);
			rootType = value;
			flag = false;
		}
		if(*item == "create-forest"){
			createForest = (*value == "true") ? true : false;
		}
		if(*item == "decode-type"){
			pool->push_back(decodeType);
			decodeType = value;
			flag = false;
		}
		if(*item == "format"){
			pool->push_back(format);
			format = value;
			flag = false;
		}
		if(*item == "punctuation"){
			vector<string*>* pv = Util::split(value, ' ');
			vector<string*>::iterator it;
			for(it = pv->begin(); it != pv->end(); it++){
				if(*(*it) != ""){
					punctSet.insert(*(*it));
				}
				pool->push_back(*it);
			}
			delete(pv);
		}
		if(*item == "coordination"){
			vector<string*>* pv = Util::split(value, ' ');
			vector<string*>::iterator it;
			for(it = pv->begin(); it != pv->end(); it++){
				if(*(*it) != ""){
					coordSet.insert(*(*it));
				}
				pool->push_back(*it);
			}
			delete(pv);
		}
		if(*item == "comma"){
			vector<string*>* pv = Util::split(value, ' ');
			vector<string*>::iterator it;
			for(it = pv->begin(); it != pv->end(); it++){
				if(*(*it) != ""){
					commaSet.insert(*(*it));
				}
				pool->push_back(*it);
			}
			delete(pv);
		}

		if(*item == "relational-features"){
			useRelationalFeatures = (*value == "true") ? true : false;
		}
		if(*item == "discourse-mode"){
			discourseMode = (*value == "true") ? true : false;
		}
		pool->push_back(item);
		if(flag && value != NULL){
			pool->push_back(value);
		}
		delete(pair);
	}
	if(NULL != trainfile){
		string tmp = "tmp/train.forest";
		trainforest = pool->get(tmp);
	}
	if(NULL != testfile){
		//testforest = pool->get(string("tmp\\test.forset"));
	}
	switch(order){
		case 1:
			if(*modelType == "dependency"){
				model = 1;
			}
			else{
				printf("model type %s is not valid for order %d\n", modelType->c_str(), order);
			}
			break;
		case 2:
			if(*modelType == "sibling"){
				model = 1;
			}
			else if(*modelType == "grandchildren"){
				model = 2;
			}
			else if(*modelType == "both"){
				model = 3;
			}
			else{
				printf("model type %s is not valid for order %d\n", modelType->c_str(), order);
			}
			break;
		case 3:
			if(*modelType == "tri-sibling"){
				model = 1;
			}
			else if(*modelType == "grand-sibling"){
				model = 2;
			}
			else if(*modelType == "both"){
				model = 3;
			}
			else{
				printf("model type %s is not valid for order %d\n", modelType->c_str(), order);
			}
			break;
		case 4:
			if(*modelType == "grand-tri-sibling"){
				model = 1;
			}
			else{
				printf("model type %s is not valid for order %d\n", modelType->c_str(), order);
			}
			break;
	}
	if(*rootType == "normal"){
		root_type = 0;
	}
	else if(*rootType == "strict"){
		root_type = 1;
	}
	else{
		printf("root type %s is not valid\n", rootType->c_str());
	}

	if(*learnModel == "MIRA"){
		lm = 0;
	}
	else if(*learnModel == "AP"){
		lm = 1;
		trainK = 1;
	}
	else if(*learnModel == "LBFGS" || *learnModel == "LBFGS-L2"){
		lm = 2;
		trainK = 1;
	}
	else if(*learnModel == "LBFGS-L1"){
		lm = 3;
		trainK = 1;
	}
	else{
		printf("learning algorithm %s is not valid\n", learnModel->c_str());
	}

}

string* ParserOptions::toString(){
	string* sb = pool->get();
	string boolean;
	sb->append("FLAGS [");
	sb->append("train-file: " + *trainfile);
	sb->append(" | ");
	sb->append("test-file: " + *testfile);
	sb->append(" | ");
	sb->append("gold-file: " + *goldfile);
	sb->append(" | ");
	sb->append("output-file: " + *outfile);
	sb->append(" | ");
	sb->append("model-name: " + *modelName);
	sb->append(" | ");
	boolean = (train ? "true" : "false");
	sb->append("train: " + boolean);
	sb->append(" | ");
	boolean = (test ? "true" : "false");
	sb->append("test: " + boolean);
	sb->append(" | ");
	boolean = (eval ? "true" : "false");
	sb->append("eval: " + boolean);
	sb->append(" | ");
	sb->append("loss-type: " + *lossType);
	sb->append(" | ");
	//boolean = (secondOrder ? "true" : "false");
	sb->append("second-order: " + boolean);
	sb->append(" | ");
	string* _numIters = Util::intToString(numIters);
	sb->append("training-iterations: " + *_numIters);
	pool->push_back(_numIters);
	sb->append(" | ");
	string* _trainK = Util::intToString(trainK);
	sb->append("training-k: " + *_trainK);
	pool->push_back(_trainK);
	sb->append(" | ");
	sb->append("decode-type: " + *decodeType);
	sb->append(" | ");
	boolean = (createForest ? "true" : "false");
	sb->append("create-forest: " + boolean);
	sb->append(" | ");
	sb->append("format: " + *format);
	sb->append(" | ");
	boolean = (useRelationalFeatures ? "true" : "false");
	sb->append("relational-features: " + boolean);
	sb->append(" | ");
	boolean = (discourseMode ? "true" : "false");
	sb->append("discourse-mode: " + boolean);
	sb->append("]\n");
	return sb;
}

ParserOptions::~ParserOptions(){
	//char command[100];
	if(trainfile != NULL){
		pool->push_back(trainfile);
		
		//strcpy(command, "del ");
		//strcat(command, trainforest->c_str());
		//system(command);
		pool->push_back(trainforest);
	}
	if(testfile != NULL){
		pool->push_back(testfile);
		/*
		strcpy_s(command, "del ");
		strcat_s(command, testforest->c_str());
		system(command);
		pool->push_back(testforest);
		*/
	}
	pool->push_back(logfile);
	pool->push_back(modelName);
	pool->push_back(lossType);
	pool->push_back(decodeType);
	pool->push_back(format);
	pool->push_back(outfile);
	pool->push_back(modelType);
	pool->push_back(rootType);
	pool->push_back(learnModel);
	if(goldfile != NULL){
		pool->push_back(goldfile);
	}
	if(devfile != NULL){
		pool->push_back(devfile);
	}
}
